#include "GAThread.h"
#include "CandidateFactory.h"
#include "Candidate.h"
#include "QDebug"
#include "Tournament.h"
#include "FitnessEvaluator.h"
#include "IslandEvolution.h"
#include "Algorithms/MelodyCandidateFactory.h"
#include "Algorithms/MelodyEvaluator.h"
#include "Algorithms/MelodyCrossover.h"
#include "ConvertGenes.h"

GAThread::GAThread(OSCthulhuClient *client) {
    this->client = client;
    this->start();
}

void GAThread::run() {
    bool finished = false;
    RandomNumberGenerator::setSeedFromSystemTime();

    /*
    //CREATE MELODY
    IslandEvolution *islandEvolution = new IslandEvolution(10,0);
    float targetValue = 3.141592653589793238462643383279;
    int generationLimit = 400;
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    50,
                    32,
                    new Tournament(0.95,0.2,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32)
            )
    );
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    50,
                    32,
                    new Tournament(0.95,0.2,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32)
            )
    );
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    50,
                    32,
                    new Tournament(0.95,0.2,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32)
            )
    );
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    50,
                    32,
                    new Tournament(0.95,0.2,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32)
            )
    );
    */

    //SEED MELODY
    IslandEvolution *islandEvolution = new IslandEvolution(1,0);
    float targetValue = 3.141592653589793238462643383279;
    int generationLimit = 1000;

    float seedGene[] = {
        3,84,577,558,499,518,0,66,536,732,344,527,2,71,793,148,120,450,0,60,734,464,319,707,7,63,370,821,205,423,1,67,630,80,458,256,2,75,12,0,455,256,3,79,462,779,117,926,3,80,871,124,363,713,7,55,995,693,602,397,7,77,889,784,318,341
    };
    float seedGene2[] = {
        3,70,857,817,161,798,3,60,857,817,161,437,1,55,135,412,480,884,7,72,857,817,491,798,3,70,857,817,161,798,7,68,857,817,491,798,7,77,857,817,491,798,7,68,857,817,491,798,7,68,857,817,491,798,2,63,738,926,823,884,4,67,208,700,730,956,3,41,857,817,161,798,4,56,857,817,161,798,7,70,857,817,491,798,2,55,738,926,823,884,2,77,833,299,173,884
    };
    float seedGene3[] = {
        2,79,43,732,597,44,2,71,973,492,120,450,2,60,734,211,360,684,1,53,630,80,458,96,2,63,370,253,205,609,2,74,252,558,499,518,2,67,857,657,458,256,3,68,367,464,954,843,3,79,662,632,411,169,7,68,529,839,720,165,7,65,889,784,61,257,1,52,630,285,458,96,2,62,671,782,127,653,2,63,538,732,168,527,2,53,310,87,551,527,6,55,705,821,88,516
    };

    std::vector<float> seedVec(seedGene,seedGene+(sizeof(seedGene)/sizeof(int)));
    std::vector<float> seedVec2(seedGene2,seedGene2+(sizeof(seedGene2)/sizeof(int)));
    std::vector<float> seedVec3(seedGene3,seedGene3+(sizeof(seedGene3)/sizeof(int)));
    std::vector<Candidate*> seedCandidates;

    //seedCandidates.push_back(new Candidate(seedVec));
    seedCandidates.push_back(new Candidate(seedVec2));
    //seedCandidates.push_back(new Candidate(seedVec3));

    /*
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    1000,
                    32,
                    new Tournament(0.85,0.015,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                    //(new MelodyCandidateFactory())->generateVariation(50,32,seedCandidates.at(0))
            )
    );
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    1000,
                    32,
                    new Tournament(0.85,0.015,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                    //(new MelodyCandidateFactory())->generateVariation(50,32,seedCandidates.at(0))

            )
    );
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    1000,
                    32,
                    new Tournament(0.85,0.015,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                    //(new MelodyCandidateFactory())->generateVariation(50,32,seedCandidates.at(0))
            )
    );
    islandEvolution->addEvolutionEngine(
            new EvolutionEngine(
                    1000,
                    32,
                    new Tournament(0.85,0.015,0.15,new MelodyCrossover(1)),
                    new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                    1,
                    (new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                    //(new MelodyCandidateFactory())->generateVariation(50,32,seedCandidates.at(0))
            )
    );

    while(!finished) {
        finished = islandEvolution->evolve();
    }
    */
    //Candidate* winner = islandEvolution->getWinner();
    Candidate* winner = seedCandidates.at(0);
    char buffer[1024];
    osc::OutboundPacketStream p( buffer, 1024 );
    p << osc::BeginMessage( "/addSyncObject" )
            <<"TestC"
            <<"Can"
            <<"MCan"
            << qPrintable(ConvertGenes::convert(winner))
            <<osc::EndMessage;
    client->sendServer(p);
    //Evolving Variations
    Candidate* referenceCandidate = winner;
    int macroGeneration = 0;
    generationLimit = 10;
    while(true) {
        macroGeneration++;
        if(macroGeneration>15) {
            macroGeneration == 0;
            delete referenceCandidate;
            referenceCandidate = winner;
        }
        finished = false;
        IslandEvolution *islandEvolution = new IslandEvolution(1,0);
        islandEvolution->addEvolutionEngine(
                new EvolutionEngine(
                        10000,
                        32,
                        new Tournament(0.95,0.0005,0.15,new MelodyCrossover(3)),
                        new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                        1,
                        //(new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                        (new MelodyCandidateFactory())->generateVariation(50,32,winner)
                )
        );
        islandEvolution->addEvolutionEngine(
                new EvolutionEngine(
                        10000,
                        32,
                        new Tournament(0.95,0.0005,0.15,new MelodyCrossover(3)),
                        new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                        1,
                        //(new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                        (new MelodyCandidateFactory())->generateVariation(50,32,winner)

                )
        );
        islandEvolution->addEvolutionEngine(
                new EvolutionEngine(
                        10000,
                        32,
                        new Tournament(0.95,0.0005,0.15,new MelodyCrossover(3)),
                        new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                        1,
                        //(new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                        (new MelodyCandidateFactory())->generateVariation(50,32,winner)
                )
        );
        islandEvolution->addEvolutionEngine(
                new EvolutionEngine(
                        10000,
                        32,
                        new Tournament(0.95,0.0005,0.15,new MelodyCrossover(3)),
                        new MelodyEvaluator(targetValue,generationLimit,minorPlus),
                        1,
                        //(new MelodyCandidateFactory())->generateInitialPopulation(50,32,seedCandidates)
                        (new MelodyCandidateFactory())->generateVariation(50,32,referenceCandidate)
                )
        );
        while(!finished) {
            finished = islandEvolution->evolve();
        }
        //delete winner;
        winner = islandEvolution->getWinner();
        //char buffer[1024];
        p.Clear();
        p << osc::BeginMessage( "/setSyncArg" )
                <<"TestC"
                << 0
                << qPrintable(ConvertGenes::convert(winner))
                << osc::EndMessage;
        client->sendServer(p);
        delete islandEvolution;
        QThread::msleep(3000);
    }


    qDebug() << "Finished!";
    exec();
}
